//使用ts实现，由一系列（x,y,z）坐标的数据，按照x的值排序并去重， 利用线性插值，创建等距的 x 坐标，步长是由用户设置的点数决定，要求多少个点，结果长度就是多少，进行插值，计算y和z的平均数 得到y和z坐标，最终得到一系列的（x,y,z）数据。
// 平均值计算
// 去重和排序：去除重复的 x 值并对数据点按 x 值排序。
// 生成等距 x 坐标：根据用户设置的点数计算步长，并生成这些等距的 x 坐标。
// 线性插值：对生成的等距 x 坐标进行插值计算 y 和 z 值。
// 计算平均值：计算插值后 y 和 z 值的平均数。

export interface Point {
  x: number;
  y: number;
  z: number;
  sn : string;
}

// 获取线性插值统计结果 - 3D版本，处理x,y,z三维数据
// aggregateMode: 1-平均，2-累加，其他-最大值
// showMode: 显示模式
// isYSum: 是否对y值进行累加
// isZSum: 是否对z值进行累加
export function GetPointInterpolated3D(points: Point[], numberOfPoints: number, aggregateMode: number, showMode: number, isYSum: boolean, isZSum: boolean) {
  const sortedPoints = removeDuplicatesAndSort(points);
  if (sortedPoints.length < 2) {
    throw new Error("At least two points are required for interpolation.");
  }
  const xMin = sortedPoints[0].x;
  const xMax = sortedPoints[sortedPoints.length - 1].x;

  //按照设备进行分组
  let group: Record<string, Point[]> = {};
  sortedPoints.map((item) => {
    if(!group.hasOwnProperty(item.sn)){
      group[item.sn] = [];
    }
    group[item.sn].push(item);
  });

  // 生成等距 x 坐标
  const equidistantX = generateEquidistantX(xMin, xMax, numberOfPoints);

  let maxY: number | null = null;
  let minY: number | null = null;
  let maxZ: number | null = null;
  let minZ: number | null = null;

  let result = [];
  for (let key in group){
    const {xys, ymax, ymin, zmax, zmin} = getInterpolateYZ(group[key], equidistantX, aggregateMode, showMode, isYSum, isZSum);
    result.push({
      sn: key,
      xys: xys,
      ymax: ymax,
      ymin: ymin,
      zmax: zmax,
      zmin: zmin
    });
    
    // 更新全局最大最小值
    if (maxY == null) maxY = ymax;
    if (minY == null) minY = ymin;
    if (maxZ == null) maxZ = zmax;
    if (minZ == null) minZ = zmin;
    
    if (ymax > maxY) maxY = ymax;
    if (ymin < minY) minY = ymin;
    if (zmax > maxZ) maxZ = zmax;
    if (zmin < minZ) minZ = zmin;
  }
  
  return {
    computeResult: result,
    maxY: minY ? maxY! : 0,
    minY: minY ? minY : 0,
    maxZ: minZ ? maxZ! : 0,
    minZ: minZ ? minZ : 0,
    xMin: xMin,
    xMax: xMax,
  };
}

// 去重和排序 - 按x值排序，去除重复的x值
function removeDuplicatesAndSort(points: Point[]): Point[] {
  const uniquePoints = Array.from(new Map(points.map(p => [p.x, p])).values());
  return uniquePoints.sort((a, b) => a.x - b.x);
}

// 生成等距 x 坐标
function generateEquidistantX(xMin: number, xMax: number, numberOfPoints: number): number[] {
  const step = (xMax - xMin) / (numberOfPoints - 1);
  return Array.from({ length: numberOfPoints }, (_, i) => xMin + i * step);
}

// 找到最近的已知点的索引
function findNearestPointsIndex(sortedPoints: Point[], x: number): [number, number] {
  const len = sortedPoints.length;
  for (let i = 0; i < len - 1; i++) {
    const p0 = sortedPoints[i];
    const p1 = sortedPoints[i + 1];
    if (x >= p0.x && x <= p1.x) {
      return [i, i + 1];
    }
  }
  // 如果 x 不在已知点的范围内，找最近的两个点
  return [0, len - 1];
}

// 获取插值后的y和z值 - 3D版本
function getInterpolateYZ(points: Point[], equidistantX: number[], aggregateMode: number, showMode: number, isYSum: boolean, isZSum: boolean) {
  const lenxEquidistant = equidistantX.length;
  let xys: Array<[number, number, number]> = []; // [x, y, z]
  let maxY: number | null = null;
  let minY: number | null = null;
  let maxZ: number | null = null;
  let minZ: number | null = null;

  let ySum = 0;
  let zSum = 0;

  for (let i = 0; i < lenxEquidistant - 1; i++) {
    const xStart = equidistantX[i];
    const xEnd = equidistantX[i + 1];
    let yEach: number | null = null;
    let zEach: number | null = null;

    // 根据聚合模式计算y值
    if (aggregateMode == 1) {
      // 平均模式
      const avgResult = averageYZInInterval(points, xStart, xEnd, showMode);
      yEach = avgResult.y;
      zEach = avgResult.z;
    } else if (aggregateMode == 2) {
      // 累加模式
      const sumResult = accumulateYZInInterval(points, xStart, xEnd, showMode);
      yEach = sumResult.y;
      zEach = sumResult.z;
    } else {
      // 最大值模式
      const maxResult = maxYZInInterval(points, xStart, xEnd, showMode);
      yEach = maxResult.y;
      zEach = maxResult.z;
    }

    if (yEach != null && zEach != null) {
      // 累加处理
      ySum += yEach;
      zSum += zEach;

      // 确定最终的y和z值
      const finalY = isYSum ? ySum : yEach;
      const finalZ = isZSum ? zSum : zEach;

      // 添加到结果数组
      xys.push([equidistantX[i], finalY, finalZ]);

      // 更新最大最小值
      if (maxY == null || finalY > maxY) maxY = finalY;
      if (minY == null || finalY < minY) minY = finalY;
      if (maxZ == null || finalZ > maxZ) maxZ = finalZ;
      if (minZ == null || finalZ < minZ) minZ = finalZ;
    }
  }
  
  return {
    xys: xys,
    ymax: maxY || 0,
    ymin: minY || 0,
    zmax: maxZ || 0,
    zmin: minZ || 0,
  };
}

// 计算区间内y和z的平均值
function averageYZInInterval(points: Point[], xStart: number, xEnd: number, showMode: number) {
  let sumY: number | null = null;
  let sumZ: number | null = null;
  let count = 0;
  const lenX = points.length;

  if (lenX <= 1) {
    return { y: 0, z: 0 };
  }

  for (let i = 0; i < lenX - 1; i++) {
    if (points[i].x >= xStart && points[i].x <= xEnd) {
      if (sumY == null) sumY = 0;
      if (sumZ == null) sumZ = 0;
      
      sumY += points[i].y;
      sumZ += points[i].z;
      count++;
    }
  }

  let yResult: number | null = null;
  let zResult: number | null = null;

  // 计算平均值
  if (count > 0) {
    if (sumY != null) yResult = sumY / count;
    if (sumZ != null) zResult = sumZ / count;
  }

  return { y: yResult ?? 0, z: zResult ?? 0 };
}

// 计算区间内y和z的累加值
function accumulateYZInInterval(points: Point[], xStart: number, xEnd: number, showMode: number) {
  let accuY: number | null = null;
  let accuZ: number | null = null;
  let count = 0;
  const lenX = points.length;

  if (lenX <= 1) {
    return { y: 0, z: 0 };
  }

  for (let i = 0; i < lenX - 1; i++) {
    if (points[i].x >= xStart && points[i].x < xEnd) {
      if (accuY == null) accuY = 0;
      if (accuZ == null) accuZ = 0;
      
      accuY += Number(points[i].y);
      accuZ += Number(points[i].z);
      count++;
    }
  }

  return { y: accuY ?? 0, z: accuZ ?? 0 };
}

// 计算区间内y和z的最大值
function maxYZInInterval(points: Point[], xStart: number, xEnd: number, showMode: number) {
  let maxY: number | null = null;
  let maxZ: number | null = null;
  let count = 0;
  const lenX = points.length;

  if (lenX <= 1) {
    return { y: 0, z: 0 };
  }

  for (let i = 0; i < lenX - 1; i++) {
    if (points[i].x >= xStart && points[i].x <= xEnd) {
      if (maxY == null || points[i].y >= maxY) maxY = points[i].y;
      if (maxZ == null || points[i].z >= maxZ) maxZ = points[i].z;
      count++;
    }
  }

  return { y: maxY ?? 0, z: maxZ ?? 0 };
}